/** @format */

let currentEffect = null

const effectStack = []

const bucket = new WeakMap()
// 新增
const effectCache = new WeakMap()
export function effect(fn, options) { // 修改
  let effectFn = effectCache.get(fn)
  if (!effectFn) {
    effectFn = () => {
      clearup(effectFn)
      effectStack.push(currentEffect)
      currentEffect = effectFn
      fn()
      currentEffect = effectStack.pop()
    }
    effectFn.deps = []
    // 新增
    effectFn.options = options
    effectCache.set(fn, effectFn)
  }
  effectFn()
}

// 响应处理
export function reactive(target) {
  return new Proxy(target, {
    set: (target, prop, value) => {
      target[prop] = value
      trigger(target, prop)
      return true
    },
    get: (target, prop) => {
      trace(target, prop)

      return target[prop]
    },
  })
}

// 清除
function clearup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i]
    deps.delete(effectFn)
  }
  effectFn.deps.length = 0
}

function trigger(target, prop) {
  const props = bucket.get(target)
  if (!props) return

  const effects = props.get(prop)
  if (!effects) return

  // 修改
  const runEffects = new Set()
  for (let fn of effects) {
    if (fn === currentEffect) continue
    runEffects.add(fn)
  }
  // 修改
  runEffects.forEach((fn) => {
    if (fn.options?.scheduler) {
      fn.options.scheduler(fn)
    } else {
      fn()
    }
  })
}

function trace(target, prop) {
  // 此处收集响应函数
  if (currentEffect) {
    let props = bucket.get(target)
    if (!props) {
      props = new Map()
      bucket.set(target, props)
    }

    let effects = props.get(prop)
    if (!effects) {
      effects = new Set()
      props.set(prop, effects)
    }

    effects.add(currentEffect)
    currentEffect.deps.push(effects)
  }
}
